Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API: Prevent large images from repeatedly crashing PHP on resize #2859

Merged
merged 1 commit into from Jul 16, 2014

Conversation

kinglozzer
Copy link
Member

See #2753 for more discussion.

This is a (late) follow up to the discussion here about GD crashing when attempting to open large or high DPI images.

The Google Group discussion involved ideas around “image unavailable” icons in the CMS, this setup (by storing which manipulation failed) will hopefully pave the way for that functionality to be added later, while addressing the immediate issue of completely crashing entire sections of websites.

Implements the same method for checking available memory as #2569, though it’s different to the method Ingo suggested. I’m not really sure which is more robust, the method in the php.net comments doesn’t take into account that bits and channels aren’t always present in the image info.

Marked as an API change as I’ve added a few methods to the Image_Backend interface.

Doesn’t cause any issues with the CMS, the images just don’t appear for now:

screen shot 2014-01-02 at 16 15 27
screen shot 2014-01-02 at 16 17 23

All comments welcome.

@Zauberfisch
Copy link
Contributor

+1 to get this done as soon as possible

great work @kinglozzer

@kinglozzer
Copy link
Member Author

I think it’s probably important that we document this change if it’s accepted, it may be quite confusing to developers otherwise if images disappear (until we set up CMS messages or something).

Would reference/image.md be the best place for this, or would it better to create a topics/image.md? Documentation on this seems more like a ‘topic’ than ‘reference’ to me, but then we’d have two separate documents for the same subject.

@kinglozzer
Copy link
Member Author

bump

I don’t wanna spend any more time on this until I get a nod of approval from a core committer. Any other comments/criticisms are also welcome of course! 😉

@Zauberfisch
Copy link
Contributor

bump

can we please get this merged asap?
Especially with those clients we deploy to shared hosting, and the ever increasing image resolution, this is becoming more and more an issue.
I have clients uploading images with a width of 6k, and they can't even delete them anymore because after the error occurred, you never get to a point in the cms where you could delete the image again.

@kinglozzer
Copy link
Member Author

bumpity bump :)

Could this (or any other proposed fix for this issue) make it into 3.2? Not sure how far off we are.


/**
* If __destruct() is called, any attempted image manipulation must have succeeded,
* so it can be removed from the cache
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't always true. HHVM at least still calls destructors after a fatal error.

@kinglozzer
Copy link
Member Author

Thanks Simon, I’d not considered that there might be inconsistencies with __destruct() like that. I’m trying to think of an alternative, but it’s quite tricky without making assumptions about how GDBackend might be used: ideally this would also cater for people who use GDBackend outside of the context of Image.

I guess you could argue that we can’t really be responsible for this - we just need to try to prevent, for example, parts of the CMS being inaccessible.

So, should we:

  • A. Not worry about how people may use GDBackend and instead only focus on Image and move some of the logic (i.e. the SS_Cache/stored manipulations logic) into there
  • B. Try to find an alternative to __destruct() and try to keep this as GD-specific as possible
  • C. Forget the __destruct() stuff, just add the approximate memory calculation to GDBackend and see if that resolves the majority of people’s issues

@Zauberfisch
Copy link
Contributor

sounds like a tricky issue.

I for one actually do use GBBackend without image as well on rare occasions, and I like to cleanly separate things if possible, but I see that there might not be a way, or it might be a lot harder, so I am fine with B.

Not sure if C is a good solution, but I am not that much into the the whole issue that I could speak to that (I don't know how accurate the approximation is, or how likely/unlikely it is that an error still occurs).
But if we can get C into core significantly faster than A or B; I would love to see C merged and A or B developed further.

@simonwelsh
Copy link
Contributor

A couple of options:

  • Remove items from the cache when writeToFile is called
  • Remove items from the cache whenever returning from one of the modifier methods

Given that it's not actually that important to remove items from the cache, I'd prefer the first option.

@kinglozzer
Copy link
Member Author

I’ve moved the cache cleaning to writeToFile() and updated a couple of other minor points.

@simonwelsh I’ve added $this->fail() to the unit tests. I wasn’t sure of the correct usage of it: it seems that a try/catch block catches the failure, so I’ve added an assertion for the exception message to make sure it’s highlighted. Is that correct?

@simonwelsh
Copy link
Contributor

Would be better to throw a more specific exception (so, a subclass) and then catch that so that the PHPUnit exception doesn't get caught.

@kinglozzer
Copy link
Member Author

Tests updated :)

simonwelsh added a commit that referenced this pull request Jul 16, 2014
API: Prevent large images from repeatedly crashing PHP on resize
@simonwelsh simonwelsh merged commit 1a63fa5 into silverstripe:master Jul 16, 2014
@simonwelsh
Copy link
Contributor

Green button pushed! Now my slides are out of date...

@Zauberfisch
Copy link
Contributor

awesome!
great work guys!

@kinglozzer
Copy link
Member Author

687474703a2f2f77696c2e746f2f5f2f7965732e676966

Thanks @simonwelsh

@kinglozzer kinglozzer deleted the gd-resize-crash-mast branch November 19, 2014 09:26
chillu added a commit to open-sausages/silverstripe-framework that referenced this pull request Jan 6, 2017
This was removed as part of the SS4 assets refactor:
silverstripe@be23989
Presumably @tractorcow didn’t feel it’s possible to retain this,
because we don’t have local file handles required for getimagesize().
Since there’s getimagesizefromstring() as well (added in PHP 5.4),
we just needed a different logic branch.

Also makes the logic more resilient against missing GD resources on a backend.
Lack of available memory for a resize is only one (new) reason,
other edge cases were already causing these missing resources (e.g. an invalid file string).

Original discussion: https://groups.google.com/forum/m/#!topic/silverstripe-dev/B57a3KYeAVQ
Pull request for 3.x: silverstripe#2859
More context: silverstripe#2569
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants